package com.cardone.platform.configuration.service;

import java.util.List;
import java.util.Map;
import java.util.UUID;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import lombok.Setter;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.transaction.annotation.Transactional;

import com.cardone.common.dto.PaginationDto;
import com.cardone.common.utils.EntityUtils;
import com.cardone.persistent.CommonDtoAttributes;
import com.cardone.platform.configuration.dao.SiteDao;
import com.cardone.platform.configuration.dao.SiteUrlDao;
import com.cardone.platform.configuration.dto.SiteDto;
import com.cardone.platform.configuration.dto.SiteUrlDto;
import com.cardone.platform.configuration.utils.DictionaryUtils;

/**
 * 站服务
 * 
 * @author yaoht
 * 
 */
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class SiteDefaultService implements SiteService {

	/**
	 * 站数据持久
	 */
	private SiteDao siteDao;

	/**
	 * 站点信息位置数据持久
	 */
	private SiteUrlDao siteUrlDao;

	@Override
	@Transactional
	@CacheEvict(value = SiteService.BEAN_ID, allEntries = true)
	public int deleteSiteByCode(@NonNull final SiteDto deleteSite) {
		return this.siteDao.deleteByCode(deleteSite, new String[] {});
	}

	@Override
	@Transactional
	@CacheEvict(value = SiteService.BEAN_ID, allEntries = true)
	public int deleteSiteByIds(@NonNull final SiteDto deleteSite) {
		return this.siteDao.deleteByIds(deleteSite);
	}

	@Override
	@Transactional
	@CacheEvict(value = SiteService.BEAN_ID, allEntries = true)
	public int deleteSiteUrlByCode(@NonNull final SiteUrlDto deleteSiteUrl) {
		return this.siteUrlDao.deleteByCode(deleteSiteUrl, new String[] {});
	}

	@Override
	@Transactional
	@CacheEvict(value = SiteService.BEAN_ID, allEntries = true)
	public int deleteSiteUrlByIds(@NonNull final SiteUrlDto deleteSiteUrl) {
		return this.siteUrlDao.deleteByIds(deleteSiteUrl);
	}

	@Override
	@Cacheable(value = SiteService.BEAN_ID, key = com.cardone.common.cache.Constants.KEY_1)
	public List<SiteDto> findListSiteByCode(@NonNull final SiteDto findListSite) {
		return this.siteDao.findListByCode(SiteDto.class, findListSite, new String[] {}, new String[] {});
	}

	@Override
	@Cacheable(value = SiteService.BEAN_ID, key = com.cardone.common.cache.Constants.KEY_1)
	public List<SiteDto> findListSiteByName(@NonNull final SiteDto findListSite) {
		return this.siteDao.findListByName(SiteDto.class, findListSite);
	}

	@Override
	@Cacheable(value = SiteService.BEAN_ID, key = com.cardone.common.cache.Constants.KEY_1)
	public List<SiteUrlDto> findListSiteUrlByCode(@NonNull final SiteUrlDto findListSiteUrl) {
		return this.siteUrlDao.findListByCode(SiteUrlDto.class, findListSiteUrl, new String[] {}, new String[] {});
	}

	@Override
	@Cacheable(value = SiteService.BEAN_ID, key = com.cardone.common.cache.Constants.KEY_1)
	public List<SiteUrlDto> findListSiteUrlByName(@NonNull final SiteUrlDto findListSiteUrl) {
		return this.siteUrlDao.findListByName(SiteUrlDto.class, findListSiteUrl);
	}

	@Override
	@Cacheable(value = SiteService.BEAN_ID, key = com.cardone.common.cache.Constants.KEY_1)
	public SiteDto findSiteByCode(@NonNull final SiteDto findSite) {
		return this.siteDao.findByCode(SiteDto.class, findSite, null, CommonDtoAttributes.id.name());
	}

	@Override
	@Cacheable(value = SiteService.BEAN_ID, key = com.cardone.common.cache.Constants.KEY_1)
	public SiteDto findSiteByCode(@NonNull final String code) {
		final SiteDto findSite = SiteDto.newSite();

		findSite.setCode(code);

		return this.siteDao.findByCode(SiteDto.class, findSite, null, new String[] { CommonDtoAttributes.code.name() });
	}

	@Override
	@Cacheable(value = SiteService.BEAN_ID, key = com.cardone.common.cache.Constants.KEY_1)
	public SiteDto findSiteById(@NonNull final SiteDto findSite) {
		return this.siteDao.findByCode(SiteDto.class, findSite, null, CommonDtoAttributes.id.name());
	}

	@Override
	@Cacheable(value = SiteService.BEAN_ID, key = com.cardone.common.cache.Constants.KEY_1)
	public SiteDto findSiteBySiteUrlCode(@NonNull final String siteUrlCode) {
		final SiteUrlDto readSiteUrl = SiteUrlDto.newSiteUrl();

		readSiteUrl.setCode(siteUrlCode);

		final String siteId = this.siteUrlDao.readByCode(String.class, SiteUrlDao.DtoAttributes.siteId.name(), readSiteUrl,
		        new String[] { CommonDtoAttributes.code.name() });

		if (StringUtils.isBlank(siteId)) {
			return null;
		}

		final SiteDto findSite = SiteDto.newSite();

		findSite.setId(siteId);

		return this.siteDao.findByCode(SiteDto.class, findSite, null, new String[] { CommonDtoAttributes.id.name() });
	}

	@Override
	@Cacheable(value = SiteService.BEAN_ID, key = com.cardone.common.cache.Constants.KEY_1)
	public SiteUrlDto findSiteUrlByCode(@NonNull final SiteUrlDto findSiteUrl) {
		return this.siteUrlDao.findByCode(SiteUrlDto.class, findSiteUrl, null, CommonDtoAttributes.id.name());
	}

	@Override
	@Cacheable(value = SiteService.BEAN_ID, key = com.cardone.common.cache.Constants.KEY_1)
	public SiteUrlDto findSiteUrlById(@NonNull final SiteUrlDto findSiteUrl) {
		return this.siteUrlDao.findByCode(SiteUrlDto.class, findSiteUrl, null, CommonDtoAttributes.id.name());
	}

	@Override
	@CacheEvict(value = SiteService.BEAN_ID, allEntries = true)
	@Transactional
	public void initSite(final List<SiteDto> initSiteList) {
		if (CollectionUtils.isEmpty(initSiteList)) {
			return;
		}

		for (final SiteDto initSite : initSiteList) {
			final String projectId = DictionaryUtils.readDictionaryIdByTypeCodeAndCode(StringUtils.EMPTY,
			        initSite.getProjectTypeCode(), initSite.getProjectCode());

			if (StringUtils.isBlank(projectId)) {
				continue;
			}

			initSite.setProjectId(projectId);

			final String styleId = DictionaryUtils.readDictionaryIdByTypeCodeAndCode(StringUtils.EMPTY, initSite.getStyleTypeCode(),
			        initSite.getStyleCode());

			if (StringUtils.isBlank(styleId)) {
				continue;
			}

			initSite.setStyleId(styleId);

			this.saveSiteByCode(initSite);
		}
	}

	@Override
	@Cacheable(value = SiteService.BEAN_ID, key = com.cardone.common.cache.Constants.KEY_1)
	public PaginationDto<SiteDto> paginationSiteByCode(@NonNull final SiteDto paginationSite) {
		return this.siteDao.paginationByCode(SiteDto.class, paginationSite);
	}

	@Override
	@Cacheable(value = SiteService.BEAN_ID, key = com.cardone.common.cache.Constants.KEY_1)
	public PaginationDto<Map<String, Object>> paginationSiteByName(@NonNull final SiteDto paginationSite) {
		return this.siteDao.paginationByName(paginationSite);
	}

	@Override
	@Cacheable(value = SiteService.BEAN_ID, key = com.cardone.common.cache.Constants.KEY_1)
	public PaginationDto<SiteUrlDto> paginationSiteUrlByCode(@NonNull final SiteUrlDto paginationSiteUrl) {
		return this.siteUrlDao.paginationByCode(SiteUrlDto.class, paginationSiteUrl);
	}

	@Override
	@Cacheable(value = SiteService.BEAN_ID, key = com.cardone.common.cache.Constants.KEY_1)
	public PaginationDto<Map<String, Object>> paginationSiteUrlByName(@NonNull final SiteUrlDto paginationSiteUrl) {
		return this.siteUrlDao.paginationByName(paginationSiteUrl);
	}

	@Override
	@Cacheable(value = SiteService.BEAN_ID, key = com.cardone.common.cache.Constants.KEY_4)
	public <T> T readSiteByCode(final Class<T> requiredType, final String objectId, final T defaultValue, final String code) {
		final SiteDto readSite = SiteDto.newSite();

		readSite.setCode(code);

		return this.siteDao.readByCode(requiredType, objectId, readSite, CommonDtoAttributes.code.name());
	}

	@Override
	@Cacheable(value = SiteService.BEAN_ID, key = com.cardone.common.cache.Constants.KEY_1)
	public Integer readSiteByCodeNqId(@NonNull final SiteDto readSite) {
		return this.siteDao.readByCodeNqId(Integer.class, readSite);
	}

	@Override
	@Cacheable(value = SiteService.BEAN_ID, key = com.cardone.common.cache.Constants.KEY_1)
	public Integer readSiteByName(@NonNull final SiteDto readSite) {
		return this.siteDao.readByName(Integer.class, null, readSite);
	}

	@Override
	@Cacheable(value = SiteService.BEAN_ID, key = com.cardone.common.cache.Constants.KEY_1)
	public Integer readSiteUrlByCodeNqId(@NonNull final SiteUrlDto readSiteUrl) {
		return this.siteUrlDao.readByCodeNqId(Integer.class, readSiteUrl);
	}

	@Override
	@Cacheable(value = SiteService.BEAN_ID, key = com.cardone.common.cache.Constants.KEY_1)
	public Integer readSiteUrlByName(@NonNull final SiteUrlDto readSiteUrl) {
		return this.siteUrlDao.readByName(Integer.class, null, readSiteUrl);
	}

	@Override
	@CacheEvict(value = SiteService.BEAN_ID, allEntries = true)
	public void reload() {
		this.siteDao.reload();

		this.siteUrlDao.reload();
	}

	@Override
	@Transactional
	@CacheEvict(value = SiteService.BEAN_ID, allEntries = true)
	public SiteDto saveSiteByCode(@NonNull final SiteDto saveSite) {
		final String[] whereAndEqProperties = EntityUtils.getWhereProperties(saveSite, CommonDtoAttributes.code.name());

		final SiteDto oldSite = this.siteDao.findByCode(SiteDto.class, saveSite, null, whereAndEqProperties);

		if (oldSite == null) {
			saveSite.setId(UUID.randomUUID().toString());

			this.siteDao.insertByCode(saveSite);

			final String[] notNullIdProperties = EntityUtils.getNotNullIdProperties(saveSite);

			return this.siteDao.findByCode(SiteDto.class, saveSite, null, notNullIdProperties);
		}

		final String[] useProperties = EntityUtils.addNotNullTimeSegmentProperties(
		        new String[] { SiteDao.DtoAttributes.projectId.name(), SiteDao.DtoAttributes.styleId.name(),
		                CommonDtoAttributes.parentId.name(), CommonDtoAttributes.typeId.name(), CommonDtoAttributes.code.name(),
		                CommonDtoAttributes.name.name(), CommonDtoAttributes.orderCode.name(), CommonDtoAttributes.value.name(),
		                CommonDtoAttributes.remark.name() }, saveSite);

		final String[] updateProperties = com.cardone.common.utils.BeanUtils.diffProperties(saveSite, oldSite, useProperties);

		if (ArrayUtils.isEmpty(updateProperties)) {
			return oldSite;
		}

		final String[] notNullIdProperties = EntityUtils.getNotNullIdProperties(oldSite);

		com.cardone.common.utils.BeanUtils.copyProperties(oldSite, saveSite, notNullIdProperties);

		this.siteDao.updateByCode(saveSite, updateProperties, notNullIdProperties);

		return this.siteDao.findByCode(SiteDto.class, oldSite, null, notNullIdProperties);
	}

	@Override
	@Transactional
	@CacheEvict(value = SiteService.BEAN_ID, allEntries = true)
	public SiteDto saveSiteByIdOrCode(@NonNull final SiteDto saveSite) {
		final String[] whereAndEqProperties = EntityUtils.getWhereProperties(saveSite, CommonDtoAttributes.code.name());

		final SiteDto oldSite = this.siteDao.findByCode(SiteDto.class, saveSite, null, whereAndEqProperties);

		if (oldSite == null) {
			saveSite.setId(UUID.randomUUID().toString());

			this.siteDao.insertByCode(saveSite);

			final String[] notNullIdProperties = EntityUtils.getNotNullIdProperties(saveSite);

			return this.siteDao.findByCode(SiteDto.class, saveSite, null, notNullIdProperties);
		}

		final String[] useProperties = EntityUtils.addNotNullTimeSegmentProperties(new String[] { CommonDtoAttributes.parentId.name(),
		        CommonDtoAttributes.typeId.name(), CommonDtoAttributes.code.name(), CommonDtoAttributes.name.name(),
		        CommonDtoAttributes.orderCode.name(), CommonDtoAttributes.value.name(), CommonDtoAttributes.remark.name() }, saveSite);

		final String[] updateProperties = com.cardone.common.utils.BeanUtils.diffProperties(saveSite, oldSite, useProperties);

		if (ArrayUtils.isEmpty(updateProperties)) {
			return oldSite;
		}

		final String[] notNullIdProperties = EntityUtils.getNotNullIdProperties(oldSite);

		com.cardone.common.utils.BeanUtils.copyProperties(oldSite, saveSite, notNullIdProperties);

		this.siteDao.updateByCode(saveSite, updateProperties, notNullIdProperties);

		return this.siteDao.findByCode(SiteDto.class, oldSite, null, notNullIdProperties);
	}

	@Override
	@Transactional
	@CacheEvict(value = SiteService.BEAN_ID, allEntries = true)
	public SiteUrlDto saveSiteUrlByIdOrCode(@NonNull final SiteUrlDto saveSiteUrl) {
		final String[] whereAndEqProperties = EntityUtils.getWhereProperties(saveSiteUrl, CommonDtoAttributes.code.name());

		final SiteUrlDto oldSiteUrl = this.siteUrlDao.findByCode(SiteUrlDto.class, saveSiteUrl, null, whereAndEqProperties);

		if (oldSiteUrl == null) {
			saveSiteUrl.setId(UUID.randomUUID().toString());

			this.siteUrlDao.insertByCode(saveSiteUrl);

			final String[] notNullIdProperties = EntityUtils.getNotNullIdProperties(saveSiteUrl);

			return this.siteUrlDao.findByCode(SiteUrlDto.class, saveSiteUrl, null, notNullIdProperties);
		}

		final String[] useProperties = EntityUtils.addNotNullTimeSegmentProperties(new String[] { CommonDtoAttributes.parentId.name(),
		        CommonDtoAttributes.typeId.name(), CommonDtoAttributes.code.name(), CommonDtoAttributes.name.name(),
		        CommonDtoAttributes.orderCode.name(), CommonDtoAttributes.value.name(), CommonDtoAttributes.remark.name() },
		        saveSiteUrl);

		final String[] updateProperties = com.cardone.common.utils.BeanUtils.diffProperties(saveSiteUrl, oldSiteUrl, useProperties);

		if (ArrayUtils.isEmpty(updateProperties)) {
			return oldSiteUrl;
		}

		final String[] notNullIdProperties = EntityUtils.getNotNullIdProperties(oldSiteUrl);

		com.cardone.common.utils.BeanUtils.copyProperties(oldSiteUrl, saveSiteUrl, notNullIdProperties);

		this.siteUrlDao.updateByCode(saveSiteUrl, updateProperties, notNullIdProperties);

		return this.siteUrlDao.findByCode(SiteUrlDto.class, oldSiteUrl, null, notNullIdProperties);
	}

	@Override
	@Transactional
	@CacheEvict(value = SiteService.BEAN_ID, allEntries = true)
	public SiteUrlDto saveSiteUrlByName(@NonNull final SiteUrlDto saveSiteUrl) {
		final String[] whereAndEqProperties = EntityUtils.getWhereProperties(saveSiteUrl, CommonDtoAttributes.code.name());

		final SiteUrlDto oldSiteUrl = this.siteUrlDao.findByCode(SiteUrlDto.class, saveSiteUrl, null, whereAndEqProperties);

		if (oldSiteUrl == null) {
			saveSiteUrl.setId(UUID.randomUUID().toString());

			this.siteUrlDao.insertByCode(saveSiteUrl);

			final String[] notNullIdProperties = EntityUtils.getNotNullIdProperties(saveSiteUrl);

			return this.siteUrlDao.findByCode(SiteUrlDto.class, saveSiteUrl, null, notNullIdProperties);
		}

		final String[] useProperties = EntityUtils.addNotNullTimeSegmentProperties(new String[] { CommonDtoAttributes.parentId.name(),
		        CommonDtoAttributes.typeId.name(), CommonDtoAttributes.code.name(), CommonDtoAttributes.name.name(),
		        CommonDtoAttributes.orderCode.name(), CommonDtoAttributes.value.name(), CommonDtoAttributes.remark.name() },
		        saveSiteUrl);

		final String[] updateProperties = com.cardone.common.utils.BeanUtils.diffProperties(saveSiteUrl, oldSiteUrl, useProperties);

		if (ArrayUtils.isEmpty(updateProperties)) {
			return oldSiteUrl;
		}

		final String[] notNullIdProperties = EntityUtils.getNotNullIdProperties(oldSiteUrl);

		com.cardone.common.utils.BeanUtils.copyProperties(oldSiteUrl, saveSiteUrl, notNullIdProperties);

		this.siteUrlDao.updateByCode(saveSiteUrl, updateProperties, notNullIdProperties);

		return this.siteUrlDao.findByCode(SiteUrlDto.class, oldSiteUrl, null, notNullIdProperties);
	}

	@Override
	@Transactional
	@CacheEvict(value = SiteService.BEAN_ID, allEntries = true)
	public int updateSiteByCode(@NonNull final SiteDto updateSite) {
		return this.siteDao.updateByCode(updateSite, new String[] {}, new String[] {});
	}

	@Override
	@Transactional
	@CacheEvict(value = SiteService.BEAN_ID, allEntries = true)
	public int updateSiteByIds(@NonNull final SiteDto updateSite) {
		return this.siteDao.updateByIds(updateSite);
	}

	@Override
	@Transactional
	@CacheEvict(value = SiteService.BEAN_ID, allEntries = true)
	public int updateSiteUrlByCode(@NonNull final SiteUrlDto updateSiteUrl) {
		return this.siteUrlDao.updateByCode(updateSiteUrl, new String[] {}, new String[] {});
	}

	@Override
	@Transactional
	@CacheEvict(value = SiteService.BEAN_ID, allEntries = true)
	public int updateSiteUrlByIds(@NonNull final SiteUrlDto updateSiteUrl) {
		return this.siteUrlDao.updateByIds(updateSiteUrl);
	}
}